using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Xml;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebControls;
using PS.WebParts.Rollup.Core;

namespace PS.WebParts.Rollup
{
    public class RollUpDataSourceView : ARollupDataSourceView
    {
        private static readonly string cellProvider=string.Empty;
        SPSite currentSite;
        protected DataTable rollUpData;
        //DataSet dsData;
        SPWeb currentWeb;
        
        //private string pageQueryString;
        
        string currentQuery;
       
        public RollUpDataSourceView(HttpContext context, IDataSource owner, string viewName)
            : base(context, owner, viewName)
        {
            base.DatesInISO8601 = true;
        }

        public SPWeb CurrentWeb
        {
            get { return currentWeb; }
        }

        public SPSite CurrentSite
        {
            get { return currentSite; }
        }

        //public string PageQueryString
        //{
        //    get
        //    {
        //        return pageQueryString;
        //    }
        //    set
        //    {
        //        pageQueryString = value;
        //    }
        //}


        override public DataTable RollUpData(SPWeb web)
        {
            currentSite = web.Site;
            currentSite.CatchAccessDeniedException = false;

            currentWeb = web;

            if (base.Scope != RollUpQueryWebScope.Web)
            {
                this.WalkSubSites(web);
            }
            else
            {
                this.VisitSite(currentWeb);
            }
            return rollUpData;
        }

        private void WalkSubSites(SPWeb web)
        {
            //dsData = GetDataSet();
            rollUpData = GetSchema();

            string[] lists = base.Lists;
            if (lists.Length == 1 && lists[0] == "*")
            {
                foreach (SPList list in web.Lists)
                {
                    string curList = list.Title;
                    ProcessList(rollUpData, web, curList, base.Fields);
                    WalkSiteCollection(web.GetSubwebsForCurrentUser(), curList);
                }
            }
            else
            {
                foreach (string list in lists)
                {
                    string curList = list;
                    if (list.LastIndexOf(':') > 0)
                    {
                        string[] arr = list.Split(new char[] { ':' });
                        using (web = GetWeb(currentSite, arr[0]))
                        {
                            curList = arr[1];
                            ProcessList(rollUpData, web, curList, base.Fields);
                            WalkSiteCollection(web.GetSubwebsForCurrentUser(), curList);
                        }
                    } else
                    {
                        ProcessList(rollUpData, web, curList, base.Fields);
                        WalkSiteCollection(web.GetSubwebsForCurrentUser(), curList);
                    }
                    
                }
            }
        }

        private SPWeb GetWeb(SPSite spSite, string url)
        {
            try
            {
                return spSite.OpenWeb(url);
            }
            catch
            {
                SPWeb web2 = SPControl.GetContextWeb(Context);
                return web2.Webs[url];
            }
        }

        private void VisitSite(SPWeb web)
        {
           // dsData = GetDataSet();
            rollUpData = GetSchema();

            string[] lists = base.Lists;
            if (lists.Length == 1 && lists[0] == "*")
            {
                foreach (SPList list in web.Lists)
                {
                    string curList = list.Title;
                    ProcessList(rollUpData, web, curList, base.Fields);
                }
            }
            else
            {
                foreach (string listName in lists)
                {
                    string curListName;
                    curListName = listName;
                    if (listName.LastIndexOf(':') > 0)
                    {
                        string[] arr = listName.Split(new char[] { ':' });
                        using (web = GetWeb(currentSite, arr[0]))
                        {
                            curListName = arr[1];
                            ProcessList(rollUpData, web, curListName, base.Fields);
                        }
                    } else
                    {
                        ProcessList(rollUpData, web, curListName, base.Fields);
                    }
                    
                }
            }
        }

        protected virtual SPQuery GetQuery(string str, SPWeb web)
        {
            SPQuery spQuery = new SPQuery();
            //cellProvider = z;

            spQuery.Query = ReplaceQueryLiveFields(str, web, base.Context, cellProvider, base.Parameters);


            if (base.QueryRecursive)
            {
                spQuery.ViewAttributes = "Scope='Recursive' ";
            }
           
            if (base.QueryModerator)
            {
                spQuery.ViewAttributes = spQuery.ViewAttributes + " ModerationType='Moderator' ";
            }
            uint? limit = base.QueryRowLimit;
            if ( limit != null)
            {
                spQuery.RowLimit = (uint)limit;
            }
            spQuery.IncludeMandatoryColumns = true;
            currentQuery = spQuery.Query;
            return spQuery;
        }

        private void ProcessList(DataTable dataTable, SPWeb web, string listName, FieldInfoCollection fields)
        {
            try
            {
                SPList spList;
                try
                {
                    spList = web.Lists[listName];
                }
                catch (ArgumentException)
                {
                    return;
                }
                if (!CanViewListItems(spList))
                {
                    return;
                }
                SPListItemCollection listItemCollection=null;
                try
                {
                    string query = base.Query;
                    if ( !string.IsNullOrEmpty( query ) )
                    {
                        listItemCollection = spList.GetItems(GetQuery(query, web));
                    }
                    else
                    {
                        listItemCollection = spList.Items;
                    }
                }
                catch (Exception exception)
                {
                    //string text3 = w;
                    //w = string.Concat(new string[] { text3, "Error: In Query <br>", GetCompleteQuery(currentQuery), "<br><br>", exception1.ToString() });
                    LogError("Error: In Query/n" +  GetCompleteQuery(currentQuery), exception );
                }
                
                if (listItemCollection == null)
                {
                    return;
                }

                
                foreach (SPListItem listItem in listItemCollection)
                {
                    DataRow row = dataTable.NewRow();
                    if (base.IncludeListData)
                    {
                        //Modifed 1/4/07 By HRamos
                        //Format the return url properly when working with an absolute url
                        string defaultViewUrl = spList.DefaultViewUrl;
                        bool absoluteUri = Uri.IsWellFormedUriString(TopLevelSite, UriKind.Absolute);
                        if (absoluteUri)
                        {
                            Uri webUri = new Uri(TopLevelSite);
                            defaultViewUrl = webUri.Scheme + "://" + webUri.Authority + defaultViewUrl;
                        }
                        row["_WebId"] = web.ID.ToString("B").ToUpper();
                        row["_ListId"] = spList.ID.ToString("B").ToUpper();
                        row["_ListTitle"] = spList.Title;
                        row["_ListUrl"] = defaultViewUrl;
                        row["_SiteTitle"] = web.Title;
                        row["_SiteUrl"] = web.Url;
                        row["_ItemId"] = listItem.ID;
                        row["_ItemUrl"] = defaultViewUrl.Substring(0, defaultViewUrl.LastIndexOf('/')) + "/DispForm.aspx?ID=" + listItem.ID;
                        row["_ItemEdit"] = defaultViewUrl.Substring(0, defaultViewUrl.LastIndexOf('/')) + "/EditForm.aspx?ID=" + listItem.ID;
                    }
                    try
                    {
                        Dictionary<string, SPField> fieldIds = new Dictionary<string, SPField>(fields.Count);
                        foreach (FieldInfo fieldInfo in fields)
                        {
                            string columnName = fieldInfo.GetSchemaName();
                            SPField spField;

                            string str = fieldInfo.InternalName;

                            if (fieldIds.ContainsKey(str))
                                spField = fieldIds[str];
                            else
                            {
                                spField = ResolveField(fieldInfo, listItem.Fields);
                                if (spField != null)
                                    fieldIds[str] = spField;
                            }

                            if (spField != null && listItem[spField.Id] != null)
                            {
                                //SPField spField = listItem.Fields.GetField(columnName);
                                DataColumnCollection tableColumns = row.Table.Columns;
                                DataColumn column = tableColumns[columnName];
                                if (!column.ExtendedProperties.ContainsKey(FieldInfo.ExtPropKey))
                                {
                                    column.ExtendedProperties.Add(FieldInfo.ExtPropKey, spField.Type);
                                }

                                string strVal = SPEncode.HtmlDecode(listItem[spField.Id].ToString().Replace("&nbsp;", " "));

                                if (!string.IsNullOrEmpty( fieldInfo.Match ))
                                {
                                    row[column] = base.GetMatchValue(columnName, fieldInfo.Match, strVal);
                                    continue;
                                }

                                if (base.DatesInISO8601
                                    //&& field.Type != SPFieldType.Text
                                    && spField.Type == SPFieldType.DateTime)
                                {
                                    strVal = XmlConvert.ToString(DateTime.Parse(strVal), XmlDateTimeSerializationMode.Unspecified); //SPUtility.CreateISO8601DateTimeFromSystemDateTime(DateTime.Parse(text2));
                                }

                                else if (base.FixLookups && (strVal.IndexOf(";#") > 0))
                                {
                                    string lookupIdColumn = columnName + "_ID";
                                    
                                    if(!tableColumns.Contains(lookupIdColumn))
                                    {
                                        DataColumn newCol = new DataColumn(lookupIdColumn, typeof(string));
                                        newCol.ExtendedProperties.Add(FieldInfo.ExtPropKey, SPFieldType.Integer);
                                        tableColumns.Add(newCol);
                                    }

                                    string lookupId = strVal.Remove(strVal.IndexOf(";#"));

                                    //int outputed;

                                    //if (int.TryParse(lookupId, out outputed))
                                        //row[lookupIdColumn] = outputed;
                                    row[lookupIdColumn] = lookupId;
                                    
                                    
                                    strVal = strVal.Substring(strVal.IndexOf(";#") + 2);
                                }
                                row[column] = strVal;
                            }
                            else
                            {
                                row[columnName] = string.Empty;
                            }
                        }
                    }
                    catch (Exception exception)
                    {
                        LogError("Rollup", exception);
                    }
                    dataTable.Rows.Add(row);
                }
            }
            catch (Exception ex)
            {
                LogError("List processing", ex);
            }
        }

        private static SPField ResolveField(FieldInfo fieldInfo, SPFieldCollection flds)
        {
            SPField spField;

            string name = fieldInfo.InternalName;

                try
                {
                    if (flds.ContainsField(name))
                    {
                        spField = flds.GetField(name);
                    }
                    else
                    {
                        name = name.Replace("_x0020_", " ");
                        spField = flds.GetField(name);
                    }
                }
                catch (ArgumentException)
                {
                    name = fieldInfo.GetCamlName();
                    try
                    {
                        spField = flds.GetFieldByInternalName(name);
                    }
                    catch (ArgumentException)
                    {
                        name =  fieldInfo.GetSchemaName().Replace(" ", "");
                        spField = flds.GetFieldByInternalName(name);
                    }
                }

            return spField;
        }


        private static bool CanViewListItems(SPList list)
        {
            try
            {
                return list.DoesUserHavePermissions(SPBasePermissions.ViewListItems);               
            }
            catch
            {
                return false;
            }
        }


        private void WalkSiteCollection(SPWebCollection webs, string listName)
        {
            foreach (SPWeb web in webs)
            {
                ProcessList(rollUpData, web, listName, base.Fields);
                WalkSiteCollection(web.GetSubwebsForCurrentUser(), listName);
                web.Dispose();
            }
        }

        private static string GetCompleteQuery(string qry)
        {
            XmlDocument document1 = new XmlDocument();
            document1.LoadXml("<query>" + qry + "</query>");
            StringBuilder builder1 = new StringBuilder();
            XmlTextWriter writer1 = new XmlTextWriter(new StringWriter(builder1));
            writer1.Formatting = Formatting.Indented;
            document1.WriteTo(writer1);
            writer1.Close();
            return builder1.ToString();
        }


        //protected DataSet GetDataSet()
        //{
        //    DataSet ds = new DataSet("Rows");
        //    rollUpData = GetSchema();
        //    ds.Tables.Add(rollUpData);
        //    return ds;
        //}

        
    }
}
